/**
 * \file IfxScuRcu.c
 * \brief SCU  basic functionality
 *
 * \version iLLD_1_0_1_17_0
 * \copyright Copyright (c) 2023 Infineon Technologies AG. All rights reserved.
 *
 *
 *
 *                                 IMPORTANT NOTICE
 *
 * Use of this file is subject to the terms of use agreed between (i) you or
 * the company in which ordinary course of business you are acting and (ii)
 * Infineon Technologies AG or its licensees. If and as long as no such terms
 * of use are agreed, use of this file is subject to following:
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer, must
 * be included in all copies of the Software, in whole or in part, and all
 * derivative works of the Software, unless such copies or derivative works are
 * solely in the form of machine-executable object code generated by a source
 * language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 *
 *
 */

/******************************************************************************/
/*----------------------------------Includes----------------------------------*/
/******************************************************************************/

#include "IfxScuRcu.h"

/******************************************************************************/
/*----------------------------------Macros------------------------------------*/
/******************************************************************************/

#define IFXSCURCU_PERFORM_RESET_DELAY (90000U)

#define IFXSCURCU_COLD_POWERON_MASK                             \
    ((IFX_SCU_RSTSTAT_STBYR_MSK << IFX_SCU_RSTSTAT_STBYR_OFF) | \
     (IFX_SCU_RSTSTAT_SWD_MSK << IFX_SCU_RSTSTAT_SWD_OFF) |     \
     (IFX_SCU_RSTSTAT_EVR33_MSK << IFX_SCU_RSTSTAT_EVR33_OFF) | \
     (IFX_SCU_RSTSTAT_EVRC_MSK << IFX_SCU_RSTSTAT_EVRC_OFF))

#define IFXSCURCU_WARM_POWERON_MASK   (IFX_SCU_RSTSTAT_PORST_MSK << IFX_SCU_RSTSTAT_PORST_OFF)

#define IFXSCURCU_ESR0_MASK           (1u << IFX_SCU_RSTSTAT_ESR0_OFF)

#define IFXSCURCU_ESR1_MASK           (1u << IFX_SCU_RSTSTAT_ESR1_OFF)

#define IFXSCURCU_SMU_MASK            (1u << IFX_SCU_RSTSTAT_SMU_OFF)

#define IFXSCURCU_SW_MASK             (1u << IFX_SCU_RSTSTAT_SW_OFF)

#define IFXSCURCU_STM0_MASK           (1u << IFX_SCU_RSTSTAT_STM0_OFF)

#if (IFXCPU_NUM_MODULES > 1U)
#define IFXSCURCU_STM1_MASK           (1u << IFX_SCU_RSTSTAT_STM1_OFF)
#endif

#if (IFXCPU_NUM_MODULES > 2U)
#define IFXSCURCU_STM2_MASK           (1u << IFX_SCU_RSTSTAT_STM2_OFF)
#endif

#if (IFXCPU_NUM_MODULES > 3U)
#define IFXSCURCU_STM3_MASK           (1u << IFX_SCU_RSTSTAT_STM3_OFF)
#endif

#if (IFXCPU_NUM_MODULES > 4U)
#define IFXSCURCU_STM4_MASK           (1u << IFX_SCU_RSTSTAT_STM4_OFF)
#endif

#if (IFXCPU_NUM_MODULES > 5U)
#define IFXSCURCU_STM5_MASK           (1u << IFX_SCU_RSTSTAT_STM5_OFF)
#endif
#define IFXSCURCU_EVRC_MASK           (1u << IFX_SCU_RSTSTAT_EVRC_OFF)

#define IFXSCURCU_EVR33_MASK          (1u << IFX_SCU_RSTSTAT_EVR33_OFF)

#define IFXSCURCU_SWD_MASK            (1u << IFX_SCU_RSTSTAT_SWD_OFF)

#define IFXSCURCU_STBYR_MASK          (1u << IFX_SCU_RSTSTAT_STBYR_OFF)

/******************************************************************************/
/*-------------------------Function Implementations---------------------------*/
/******************************************************************************/

IfxScuRcu_ResetCode IfxScuRcu_evaluateReset(void)
{
    Ifx_SCU_RSTCON      Rstcon;
    Ifx_SCU_RSTSTAT     RstStat;
    IfxScuRcu_ResetCode resetCode;
    resetCode.cpuSafeState = (((MODULE_SCU.RSTCON2.U >> IFX_SCU_RSTCON2_CSSX_OFF) & IFX_SCU_RSTCON2_CSSX_MSK) == IFX_SCU_RSTCON2_CSSX_MSK);
    resetCode.resetType    = IfxScuRcu_ResetType_undefined;
    resetCode.resetTrigger = IfxScuRcu_Trigger_undefined;
    resetCode.resetReason  = 0;

    RstStat.U              = MODULE_SCU.RSTSTAT.U;
    Rstcon.U               = MODULE_SCU.RSTCON.U;

    /* Evaluate the warm reset conditions first */
    if (RstStat.B.ESR0)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.ESR0;
        resetCode.resetTrigger = IfxScuRcu_Trigger_esr0;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.ESR1)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.ESR1;
        resetCode.resetTrigger = IfxScuRcu_Trigger_esr1;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.SMU)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.SMU;
        resetCode.resetTrigger = IfxScuRcu_Trigger_smu;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.SW)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.SW;
        resetCode.resetTrigger = IfxScuRcu_Trigger_sw;
        resetCode.resetReason  = MODULE_SCU.RSTCON2.B.USRINFO;
    }
    else if (RstStat.B.STM0)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM0;
        resetCode.resetTrigger = IfxScuRcu_Trigger_stm0;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.STM1)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM1;
        resetCode.resetTrigger = IfxScuRcu_Trigger_stm1;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.STM2)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM2;
        resetCode.resetTrigger = IfxScuRcu_Trigger_stm2;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.STM3)
    {
        resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM3;
        resetCode.resetTrigger = IfxScuRcu_Trigger_stm3;
        resetCode.resetReason  = 0;
    }

    else if (RstStat.B.CB0)
    {
        resetCode.resetType    = IfxScuRcu_ResetType_system;
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb0;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.CB1)
    {
        resetCode.resetType    = IfxScuRcu_ResetType_debug;
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb1;
        resetCode.resetReason  = 0;
    }
    else if (RstStat.B.CB3)
    {
        resetCode.resetType    = IfxScuRcu_ResetType_application;
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb3;
        resetCode.resetReason  = 0;
    }
    else
    {
        /* Now evaluate for Cold reset conditions */
        if (RstStat.B.EVRC)
        {
            resetCode.resetType    = IfxScuRcu_ResetType_coldpoweron;
            resetCode.resetTrigger = IfxScuRcu_Trigger_evrc;
            resetCode.resetReason  = 0;
        }
        else if (RstStat.B.EVR33)
        {
            resetCode.resetType    = IfxScuRcu_ResetType_coldpoweron;
            resetCode.resetTrigger = IfxScuRcu_Trigger_evr33;
            resetCode.resetReason  = 0;
        }
        else if (RstStat.B.SWD)
        {
            resetCode.resetType    = IfxScuRcu_ResetType_coldpoweron;
            resetCode.resetTrigger = IfxScuRcu_Trigger_swd;
            resetCode.resetReason  = 0;
        }
        else if (RstStat.B.STBYR)
        {
            resetCode.resetType    = IfxScuRcu_ResetType_coldpoweron;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stbyr;
            resetCode.resetReason  = 0;
        }
    }

/* Finally - Evaluate selectively for PORST */
    if (RstStat.B.PORST)
    {
        if (resetCode.resetType != IfxScuRcu_ResetType_coldpoweron)
        {
            resetCode.resetType    = IfxScuRcu_ResetType_warmpoweron;
            resetCode.resetTrigger = IfxScuRcu_Trigger_portst;
        }

        resetCode.resetReason = 0;
    }

    return resetCode;
}


void IfxScuRcu_performReset(IfxScuRcu_ResetType resetType, uint16 userResetInfo)
{
    uint32 index;
    uint16 password;

    password = IfxScuWdt_getSafetyWatchdogPassword();
    IfxScuWdt_clearSafetyEndinitInline(password);

    /* Write the Reset Type - Application or System Reset */
    if (IfxScuRcu_ResetType_system == resetType)
    {
        MODULE_SCU.RSTCON.B.SW = 1; /* System Reset */
    }
    else
    {
        MODULE_SCU.RSTCON.B.SW = 2; /* Application Reset */
    }

    /* SWRSTCON and RSTCON2 are CPU endinit protected - clear end init protection */
    password = IfxScuWdt_getCpuWatchdogPasswordInline(&MODULE_SCU.WDTCPU[IfxCpu_getCoreIndex()]);

    IfxScuWdt_clearCpuEndinitInline(&MODULE_SCU.WDTCPU[IfxCpu_getCoreIndex()], password);
    /* Write the user DATA to reset evaluation */
    MODULE_SCU.RSTCON2.B.USRINFO = userResetInfo;

    /* software Reset can be performed by writing to Reset Request register  SWRSTCON */
    MODULE_SCU.SWRSTCON.B.SWRSTREQ = 1U;

    /* Add some delay for HW to reset */
    for (index = 0U; index < (uint32)IFXSCURCU_PERFORM_RESET_DELAY; index++)
    {}

    /*IfxScu_Wdt_enableSafetyEndinit() is not needed, as the micro would RESET */
    /* IfxScuWdt_setCpuEndinitInline() is not needed, as the micro would RESET */
}


IfxScuRcu_ResetCode IfxScuRcu_getResetReason(void)
{
    Ifx_SCU_RSTCON      Rstcon;
    Ifx_SCU_RSTSTAT     RstStat;
    IfxScuRcu_ResetCode resetCode;

    uint32              cldRbits  = 0u;
    uint32              warmRbits = 0u;
    uint32              asRbits   = 0u;

    resetCode.cpuSafeState = (((MODULE_SCU.RSTCON2.U >> IFX_SCU_RSTCON2_CSSX_OFF) & IFX_SCU_RSTCON2_CSSX_MSK) == IFX_SCU_RSTCON2_CSSX_MSK);
    resetCode.resetType    = IfxScuRcu_ResetType_undefined;
    resetCode.resetTrigger = IfxScuRcu_Trigger_undefined;
    resetCode.resetReason  = 0;

    RstStat.U              = MODULE_SCU.RSTSTAT.U;
    Rstcon.U               = MODULE_SCU.RSTCON.U;

    cldRbits               = RstStat.U & IFXSCURCU_COLD_POWERON_MASK;
    warmRbits              = RstStat.U & IFXSCURCU_WARM_POWERON_MASK;
    asRbits                = RstStat.U & IFXSCURCU_APPLICATIONRESET_MASK;

    /* Evaluate Cold power on reset */
    if ((cldRbits != 0u) && (warmRbits != 0u) && (asRbits == 0u))  /* Cold Power On */
    {
        resetCode.resetType = IfxScuRcu_ResetType_coldpoweron;

        switch (cldRbits)
        {
        case IFXSCURCU_EVRC_MASK:
            resetCode.resetTrigger = IfxScuRcu_Trigger_evrc;
            break;

        case IFXSCURCU_EVR33_MASK:
            resetCode.resetTrigger = IfxScuRcu_Trigger_evr33;
            break;

        case IFXSCURCU_SWD_MASK:
            resetCode.resetTrigger = IfxScuRcu_Trigger_swd;
            break;

        case IFXSCURCU_STBYR_MASK:
            resetCode.resetTrigger = IfxScuRcu_Trigger_stbyr;
            break;

        default:
            resetCode.resetTrigger = IfxScuRcu_Trigger_undefined;
            break;
        }
    }
    else if ((cldRbits == 0u) && (warmRbits != 0u) && (asRbits == 0u)) /* Warm Power On */
    {
        resetCode.resetType    = IfxScuRcu_ResetType_warmpoweron;
        resetCode.resetTrigger = IfxScuRcu_Trigger_portst;
    }
    else if ((cldRbits == 0u) && (warmRbits == 0u) && (asRbits != 0u)) /* App/Sys resets */
    {
        switch (asRbits)
        {
        case IFXSCURCU_ESR0_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.ESR0;
            resetCode.resetTrigger = IfxScuRcu_Trigger_esr0;
            break;

        case IFXSCURCU_ESR1_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.ESR1;
            resetCode.resetTrigger = IfxScuRcu_Trigger_esr1;
            break;

        case IFXSCURCU_SMU_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.SMU;
            resetCode.resetTrigger = IfxScuRcu_Trigger_smu;
            break;

        case IFXSCURCU_SW_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.SW;
            resetCode.resetTrigger = IfxScuRcu_Trigger_sw;
            break;

        case IFXSCURCU_STM0_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM0;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm0;
            break;

#if (IFXCPU_NUM_MODULES > 1U)
        case IFXSCURCU_STM1_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM1;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm1;
            break;
#endif

#if (IFXCPU_NUM_MODULES > 2U)
        case IFXSCURCU_STM2_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM2;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm2;
            break;
#endif

#if (IFXCPU_NUM_MODULES > 3U)
        case IFXSCURCU_STM3_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM3;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm3;
            break;
#endif

#if (IFXCPU_NUM_MODULES > 4U)
        case IFXSCURCU_STM4_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM4;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm4;
            break;
#endif

#if (IFXCPU_NUM_MODULES > 5U)
        case IFXSCURCU_STM5_MASK:
            resetCode.resetType    = (IfxScuRcu_ResetType)Rstcon.B.STM5;
            resetCode.resetTrigger = IfxScuRcu_Trigger_stm5;
            break;
#endif
        default:
            resetCode.resetTrigger = IfxScuRcu_Trigger_undefined;
            break;
        }
    }
    else if ((cldRbits != 0u) || ((warmRbits != 0u) && (asRbits != 0u)))
    {
        resetCode.resetType = IfxScuRcu_ResetType_undefined;
    }
    else if ((cldRbits == 0u) && ((warmRbits != 0u) && (asRbits != 0u)))
    {
        resetCode.resetType = IfxScuRcu_ResetType_undefined;
    }
    else if (RstStat.B.CB0)
    {
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb0;
        resetCode.resetType    = IfxScuRcu_ResetType_system;
    }
    else if (RstStat.B.CB1)
    {
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb1;
        resetCode.resetType    = IfxScuRcu_ResetType_debug;
    }
    else if (RstStat.B.CB3)
    {
        resetCode.resetTrigger = IfxScuRcu_Trigger_cb3;
        resetCode.resetType    = IfxScuRcu_ResetType_application;
    }

    return resetCode;
}
